package com.xzj.spring.utils;

import com.xzj.spring.entity.DefaultAnnotationAttributeExtractor;

import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;

/**
 * @ProjectName: SpringDemo
 * @Package: com.xzj.spring.utils
 * @ClassName: AnnotationUtil
 * @Author: xzj
 * @Description:
 * @Date: 2022/7/14 18:00
 * @Version: 1.0
 */
public class AnnotationUtil {

    /**
     * @param clz         需要找的注解
     * @param annotations
     * @return
     * @Author xzj
     * @Description 判断有没有被注解标注  包括组合注解中是否有   多级递归查询 和AnnotationUtil中的方法不一致
     * @Date 11:44 2022/7/14
     **/
    public static boolean findAnnotation(Class<?> clz, Annotation[] annotations) {
        for (Annotation annotation : annotations) {
            //如果是元注解直接跳过 因为这些注解的元注解还是他本身 递归调用会死循环
            if (annotation.annotationType() == Retention.class
                    || annotation.annotationType() == Target.class
                    || annotation.annotationType() == Documented.class
            ) {
                continue;
            }

            if (clz == annotation.annotationType()) {
                return true;
            }
            Annotation[] parentAnnotations = annotation.annotationType().getAnnotations();
            if (findAnnotation(clz, parentAnnotations)) {
                return true;
            }
        }
        return false;
    }

    /**
     * @Author xzj
     * @Description 从clz或方法上拿  包含annotationClass这个注解的注解  比如
     *
     *   列如：  @RestController
     *          @RequestMapping("/hello")
     *          public class HelloController {}
     *
     *          getAnnotation(HelloController.class,Controller.class)
     *          返回  Annotation @RestController
     *
     *
     * @Date 18:06 2022/7/14
     * @param annotatedElement
     * @param annotationClass
     * @return
     **/
    public static<A extends Annotation> A getAnnotation(AnnotatedElement annotatedElement, Class<A> annotationClass)  {
        A annotation = annotatedElement.getAnnotation(annotationClass);
        //如果直接拿没有 说明在父类注解
        if(annotation == null){
            Annotation[] annotations = annotatedElement.getAnnotations();
            for (Annotation an : annotations) {
                if(findAnnotation(annotationClass,an.annotationType().getAnnotations())){
                    DefaultAnnotationAttributeExtractor defaultAnnotationAttributeExtractor = new DefaultAnnotationAttributeExtractor(an);
                    return (A) Proxy.newProxyInstance(an.annotationType().getClassLoader(), new Class[]{annotationClass},new SynthesizedAnnotationInvocationHandler(defaultAnnotationAttributeExtractor));
                }
            }
            return null;
        }
        return annotation;
    }

    /**
     * @Author xzj
     * @Description 代理对象handle
     * @Date 12:45 2022/7/15
     * @return
     **/
    private static class SynthesizedAnnotationInvocationHandler implements InvocationHandler {
        Map<String, Object> attributeMap ;

        public SynthesizedAnnotationInvocationHandler(DefaultAnnotationAttributeExtractor attributeExtractor) {
            attributeMap = attributeExtractor.getAttributeMap();
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return attributeMap.get(method.getName());
        }
    }
}
